package com.dhj.yygh.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dhj.yygh.listener.DictListener;
import com.dhj.yygh.mapper.DictMapper;
import com.dhj.yygh.model.cmn.Dict;
import com.dhj.yygh.service.DictService;
import com.dhj.yygh.vo.cmn.DictEeVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class DictServiceImpl extends ServiceImpl<DictMapper, Dict> implements DictService {

//    @Autowired
//    DictMapper dictMapper; // 此处不需要再注入 DictMapper，因为 ServiceImpl 中已经自动注入了

    @Override
    /*
    @Cacheable 通过该注解将查询出的数据(方法返回值)放入缓存中，其参数代表
    value 缓存名，指定一个缓存的命名空间，以区分不同区域的缓存
    keyGenerator 缓存的key,参数为指定的 key 生成器，一般在配置类中配置该生成器
    实质上 redis 中的 key 是将 value 和 keyGenerator 生成的 key 进行拼接
     */
    // @Cacheable(value = "dict", keyGenerator = "keyGenerator")
    // 根据 id 查询其子 id 对应的数据
    public List<Dict> getChildDataById(Long id) {

        QueryWrapper<Dict> wrapper = new QueryWrapper<>();

        // 查询其 parent_id 为指定 id 的数据,也就是查询某个 id 的所有子节点
        wrapper.eq("parent_id", id);

        List<Dict> dicts = baseMapper.selectList(wrapper);

        // 遍历子节点的数据，为其 hasChildren 属性赋值
        for (Dict dict : dicts) {
            // 判断其 id 是否有子节点
            if (isChild(dict.getId())) {
                // 设置其 hasChildren 属性
                dict.setHasChildren(true);
            } else {
                dict.setHasChildren(false);
            }
        }
        return dicts;
    }


    // 判断 id 下面是否有子节点
    private boolean isChild(Long id) {
        QueryWrapper<Dict> wrapper = new QueryWrapper<>();

        wrapper.eq("parent_id", id);

        return baseMapper.selectCount(wrapper) > 0;
    }

    //数据字典数据导出
    @Override
    public void exportDictData(HttpServletResponse resp) {
        resp.setContentType("application/vnd.ms-excel");
        resp.setCharacterEncoding("utf-8");

        // 这里 URLEncoder.encode 只是为了防止中文乱码,和 easyexcel 没有关系
        //String fileName = URLEncoder.encode("数据字典", "UTF-8");

        String fileName = "dictdata";// 使用英文，避免因字符集产生异常
        resp.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");

        List<Dict> dicts = baseMapper.selectList(null);

        ArrayList<DictEeVo> dictEeVos = new ArrayList<>();

        // Dict 和 DictEeVo 进行转化
        for (Dict dict : dicts) {
            DictEeVo dictEeVo = new DictEeVo();
            BeanUtils.copyProperties(dict, dictEeVo);
            dictEeVos.add(dictEeVo);
        }
        try {
            EasyExcel.write(resp.getOutputStream(), DictEeVo.class).sheet("dictdemo").doWrite(dictEeVos);
        } catch (IOException e) {
            e.printStackTrace();
        }


    }

    // 数据字典导入数据库
    @Override
    /*
    @CacheEvict 清空缓存，此处在导入操作执行完成后，清空缓存，保持数据的更新
    value 标识缓存所在的区域(命名空间)
    allEntries 清空所有缓存
     */
    //@CacheEvict(value = "dict", allEntries = true)
    public void importDictData(MultipartFile file) {
        try {
            EasyExcel.read(file.getInputStream(), DictEeVo.class, new DictListener(baseMapper)).sheet().doRead();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /*
     根据 dictCode && value 查询 dict 中数据
     因为诸如医院等级等数据其 value 值不唯一，需要通过 dict_code 联合查询
     */
    @Override
    public String getDictDataByDictcodeAndValue(String dictcode, String value) {

        QueryWrapper<Dict> wrapper = new QueryWrapper<>();

        // dectCode 代表的是父节点，根据 dectCode 查询整行父节点的数据
        wrapper.eq("dict_code", dictcode);
        Dict dict = baseMapper.selectOne(wrapper);

        Long id = dict.getId();

        QueryWrapper<Dict> wrapper1 = new QueryWrapper<>();

        // 通过 parent_id 可以定位到医院等级的所有子节点
        wrapper1.eq("parent_id", id)

                // 通过其子节点的 value 再次构造查询条件
                .eq("value", value);


        // 最终获取指定子节点的 name 值
        Dict dict1 = baseMapper.selectOne(wrapper1);

        return dict1.getName();
    }

    // 根据 value 查询 dict 中数据
    @Override
    public String getDictByValue(String value) {

        QueryWrapper<Dict> wrapper = new QueryWrapper<>();

        // 省市区等数据其 value 值是唯一的，直接通过 value 值查询即可
        wrapper.eq("value", value);

        Dict dict = baseMapper.selectOne(wrapper);

        return dict.getName();
    }

    // 根据 ditc_code 查询其子节点信息
    @Override
    public List<Dict> getChildByDictCode(String dict_code) {

        // 首先根据 dict_code 查到该数据的 id 值
        QueryWrapper<Dict> wrapper = new QueryWrapper<>();

        wrapper.eq("dict_code", dict_code);

        Dict dict = baseMapper.selectOne(wrapper);

        // 获取其 id 值
        Long id = dict.getId();

        // 查询其 parent_id 为 指定 id 的所有数据
        QueryWrapper<Dict> wrapper1 = new QueryWrapper<>();

        wrapper1.eq("parent_id", id);

        List<Dict> dicts = baseMapper.selectList(wrapper1);

        return dicts;
    }
}
